package uk.co.agileworks.bidpirate.service;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.text.DecimalFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.htmlunit.HtmlUnitDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import uk.co.agileworks.bidpirate.model.CurrencyAndPrice;
import uk.co.agileworks.bidpirate.model.Item;

@Service
public final class EbayFacadeImpl implements EbayFacade {

	private static final Logger LOGGER = LoggerFactory.getLogger(EbayFacadeImpl.class);

	private static final boolean ENABLE_JAVASCRIPT = false;
	private static final String EBAY_FORMAT = "MM/dd/yyyy hh:mm:ss a";
	private static final int HOURS_TO_UK = 8;

	@Autowired
	private ApplicationContext ctx;

	@Resource
	private String viewItemUrl;

	@Override
	public CurrencyAndPrice extractCurrencyAndPrice(String currencyAndPriceText) {
		return getCurrencyAndPrice(currencyAndPriceText);
	}

	@Override
	public String extractDescription(String title) {
		String description = StringUtils.substringBefore(title, " - eBay Mobile");
		LOGGER.debug("description=" + description);
		return description;
	}

	@Override
	public DateTime extractEndTime(String title) {
		Pattern pattern = Pattern.compile("\\d*/\\d*/\\d* \\d*:\\d*:\\d* \\D\\D");
		Matcher matcher = pattern.matcher(title);
		if (matcher.find()) {
			String endTimePacific = title.substring(matcher.start(), matcher.end());
			LOGGER.debug("endTimePacific=" + endTimePacific);
			DateTimeFormatter formatter = DateTimeFormat.forPattern(EBAY_FORMAT);
			return formatter.parseDateTime(endTimePacific).plusHours(HOURS_TO_UK);
		} else {
			throw new IllegalStateException("End time not found.");
		}
	}

	@Override
	public String extractImageUrl(String imageSrc) {
		String encodedUrl = StringUtils.substringAfter(imageSrc, "url=");
		LOGGER.debug("encodedUrl=" + encodedUrl);
		try {
			return URLDecoder.decode(encodedUrl, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new IllegalStateException(e);
		}
	}

	@Override
	public long extractItemNumber(String title) {
		Pattern pattern = Pattern.compile("\\d{12}");
		Matcher matcher = pattern.matcher(title);
		if (matcher.find()) {
			String itemNumber = title.substring(matcher.start(), matcher.end());
			LOGGER.debug("itemNumber=" + itemNumber);
			return Long.parseLong(itemNumber);
		} else {
			throw new ServiceException("itemNumber.invalid");
		}
	}

	@Override
	public String getItemUrl(long itemNumber) {
		String itemUrl = viewItemUrl.replace("%ITEM_NUMBER%", String.valueOf(itemNumber));
		LOGGER.debug("itemUrl=" + itemUrl);
		return itemUrl;
	}

	@Override
	public EbaySession newEbaySession() {
		return ctx.getBean(EbaySession.class);
	}

	@Override
	public String parseCurrencyAndPriceOnly(String itemUrl) {
		WebDriver driver = new HtmlUnitDriver(ENABLE_JAVASCRIPT);
		driver.get(itemUrl);
		WebElement currencyAndPriceSpan = getCurrencyAndPriceSpan(driver);
		return currencyAndPriceSpan.getText();
	}
	
	@Override
	public Item parseItem(String itemUrl) {
		WebDriver driver = new HtmlUnitDriver(ENABLE_JAVASCRIPT);
		driver.get(itemUrl);
		String title = driver.getTitle();
		LOGGER.debug("title=" + title);
		Item item = new Item();
		item.setItemNumber(extractItemNumber(title));
		item.setDescription(extractDescription(title));
		item.setEndTime(extractEndTime(title));

		WebElement currencyAndPriceSpan = getCurrencyAndPriceSpan(driver);
		item.setCurrencyAndPrice(extractCurrencyAndPrice(currencyAndPriceSpan.getText()));

		try {
			WebElement image = driver.findElement(By
					.xpath("//div[@id='Status']/div/table/tbody/tr/td/img"));
			String imageSrc = image.getAttribute("src");
			LOGGER.debug("imageSrc=" + imageSrc);
			item.setImageUrl(extractImageUrl(imageSrc));
		} catch (NoSuchElementException e) {
			item.setImageUrl("static/image_not_available.gif");
		}
		boolean buyItNow = false;
		try {
			driver.findElement(By.xpath("//span[@id='ButtonBid']"));
		} catch (NoSuchElementException e) {
			buyItNow = true;
		}
		LOGGER.debug("buyItNow=" + buyItNow);
		item.setBuyItNow(buyItNow);
		return item;
	}

	static CurrencyAndPrice getCurrencyAndPrice(String currencyAndPriceText) {
		try {
			Pattern pattern = Pattern.compile("\\d");
			Matcher matcher = pattern.matcher(currencyAndPriceText);
			matcher.find();
			String currencyPart = currencyAndPriceText.substring(0, matcher.start());
			LOGGER.debug("currencyPart=" + currencyPart);
			String pricePart = currencyAndPriceText.substring(matcher.start());
			LOGGER.debug("pricePart=" + pricePart);
			double price = new DecimalFormat().parse(pricePart).doubleValue();
			return new CurrencyAndPrice(currencyPart, price);
		} catch (Exception e) {
			throw new IllegalArgumentException(e);
		}
	}

	static WebElement getCurrencyAndPriceSpan(WebDriver driver) {
		WebElement currencyAndPrice = driver.findElement(By
				.xpath("//div[@id='Content']/div[2]/table/tbody/tr[2]/td[2]/span"));
		LOGGER.debug("currencyAndPrice=" + currencyAndPrice.getText());
		return currencyAndPrice;
	}

}
